use std::ffi::{CStr, OsString};
use std::io::{IoSlice, IoSliceMut};
use std::os::windows::io::{AsRawHandle, RawHandle};
use std::path::{Path, PathBuf};
use std::time::Duration;

use winapi::shared::minwindef::{BOOL, HKEY};
use winapi::shared::winerror;
use winapi::um::{   winnt, winreg};


#[derive(Debug)]
struct RegKey {
	key: HKEY,
}

impl RegKey {
	fn open(parent: HKEY, subpath: &CStr, rights: winreg::REGSAM) -> std::io::Result<Self> {
		unsafe {
			let mut key: HKEY = std::ptr::null_mut();
			let status = winreg::RegOpenKeyExA(parent, subpath.as_ptr(), 0, rights, &mut key);
			if status != 0 {
				Err(std::io::Error::from_raw_os_error(status))
			} else {
				Ok(Self { key })
			}
		}
	}

	fn get_value_info(&self) -> std::io::Result<(u32, u32, u32)> {
		unsafe {
			let mut value_count: u32 = 0;
			let mut max_value_name_len: u32 = 0;
			let mut max_value_data_len: u32 = 0;
			let status = winreg::RegQueryInfoKeyA(
				self.key,
				std::ptr::null_mut(),
				std::ptr::null_mut(),
				std::ptr::null_mut(),
				std::ptr::null_mut(),
				std::ptr::null_mut(),
				std::ptr::null_mut(),
				&mut value_count,
				&mut max_value_name_len,
				&mut max_value_data_len,
				std::ptr::null_mut(),
				std::ptr::null_mut(),
			);
			if status != 0 {
				Err(std::io::Error::from_raw_os_error(status))
			} else {
				Ok((value_count, max_value_name_len, max_value_data_len))
			}
		}
	}

	fn get_string_value(
		&self,
		index: u32,
		max_name_len: u32,
		max_data_len: u32,
	) -> std::io::Result<Option<(Vec<u8>, Vec<u8>)>> {
		unsafe {
			let mut name = vec![0u8; max_name_len as usize + 1];
			let mut data = vec![0u8; max_data_len as usize];
			let mut name_len = name.len() as u32;
			let mut data_len = data.len() as u32;
			let mut kind = 0;
			let status = winreg::RegEnumValueA(
				self.key,
				index,
				name.as_mut_ptr().cast(),
				&mut name_len,
				std::ptr::null_mut(),
				&mut kind,
				data.as_mut_ptr().cast(),
				&mut data_len,
			);
			if status == winerror::ERROR_NO_MORE_ITEMS as i32 {
				Ok(None)
			} else if status != 0 {
				Err(std::io::Error::from_raw_os_error(status))
			} else if kind != winnt::REG_SZ {
				Ok(None)
			} else {
				name.truncate(name_len as usize + 1);
				data.truncate(data_len as usize);
				Ok(Some((name, data)))
			}
		}
	}
}

impl Drop for RegKey {
	fn drop(&mut self) {
		unsafe {
			winreg::RegCloseKey(self.key);
		}
	}
}
